package com.rritw.webtools.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Node;

import com.rritw.webtools.common.Const;
import com.rritw.webtools.common.HttpResult;

/**
 * HttpClient工具类
 * 
 * @author ddp1j32
 * @date 2015-2-5
 */
public class HttpClientUtil {

    private static final Pattern               CHARSET_PATTERN = Pattern.compile("charset=(.+)\">");
    private static final HttpConnectionManager connectionManager;

    private static final HttpClient            client;
    /** 初使化 **/
    static {

        HttpConnectionManagerParams params = loadHttpConfFromFile();

        connectionManager = new MultiThreadedHttpConnectionManager();

        connectionManager.setParams(params);

        client = new HttpClient(connectionManager);

        client.getHostConfiguration().getParams().setParameter("http.default-headers", getHttpDefaultHeader());
    }

    /**
     * 返回默认的Http Client Header
     * 
     * @throws IOException
     */
    public static List<Header> getHttpDefaultHeader() {
        List<Header> headers = new ArrayList<Header>();
        headers.add(new Header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"));
        headers.add(new Header("Accept-Charset", "GBK,utf-8;q=0.7,*;q=0.3"));
        // headers.add(new Header("Accept-Encoding", "gzip,deflate,sdch"));
        // 如果支持gzip，那么就要对获取的内容进行判断是否是gzip格式，否则会出错
        headers.add(new Header("Accept-Encoding", "gzip,deflate,sdch"));
        headers.add(new Header("Accept-Language", "zh-CN,zh;q=0.8"));
        headers.add(new Header("Cache-Contro", "max-age=0"));
        headers.add(new Header("Connection", "keep-alive"));
        headers.add(new Header("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.8 (KHTML, like Gecko; Google Web Preview) Chrome/19.0.1084.36 Safari/536.8"));
        return headers;
    }

    /**
     * 初使化连接参数
     * 
     * @return
     */
    private static HttpConnectionManagerParams loadHttpConfFromFile() {
        Properties p = new Properties();
        try {
            p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
        } catch (IOException e) {
        }

        HttpConnectionManagerParams params = new HttpConnectionManagerParams();
        params.setConnectionTimeout(Integer.parseInt(p.getProperty("http.connection.timeout")));
        params.setSoTimeout(Integer.parseInt(p.getProperty("http.so.timeout")));
        params.setStaleCheckingEnabled(Boolean.parseBoolean(p.getProperty("http.stale.check.enabled")));
        params.setTcpNoDelay(Boolean.parseBoolean(p.getProperty("http.tcp.no.delay")));
        params.setDefaultMaxConnectionsPerHost(Integer.parseInt(p.getProperty("http.default.max.connections.per.host")));
        params.setMaxTotalConnections(Integer.parseInt(p.getProperty("http.max.total.connections")));
        params.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(0, false));
        return params;
    }

    /**
     * 发起Post请求，并返回SdkHttpResult对象
     * 
     * @param url 请求的URL地址
     * @param content 发送的内容
     * @return
     * @throws HttpException
     * @throws IOException
     */
    public static HttpResult doPost(String url, String content) throws HttpException, IOException {
        PostMethod method = new PostMethod(UrlUtil.prettyUrl(url));
        try {
            RequestEntity requestEntity = new ByteArrayRequestEntity(content.getBytes(Const.CHARSET));

            method.addRequestHeader("Connection", "Keep-Alive");
            method.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
            method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(0, false));
            method.setRequestEntity(requestEntity);
            method.addRequestHeader("Content-Type", "application/x-www-form-urlencoded");

            int statusCode = client.executeMethod(method);
            String result = getResult(method);
            return new HttpResult(statusCode, result, method.getResponseHeaders());
        } finally {
            method.releaseConnection();
        }
    }

    public static HttpClient getClient() {
        return client;
    }

    /**
     * 通过get方法获取网页内容
     * 
     * @param url 获取内容的URL
     * @param resultWithHeader 响应的内容是否带响应头
     * @return 根据当前的URL，获取到的网页的内容
     * @throws IOException
     * @throws HttpException
     */
    public static HttpResult doGet(String url) throws HttpException, IOException {
        GetMethod method = new GetMethod(UrlUtil.prettyUrl(url));
        method.setFollowRedirects(true);

        try {
            int statusCode = client.executeMethod(method);
            String result = getResult(method);
            return new HttpResult(statusCode, result, method.getResponseHeaders());
        } finally {
            method.releaseConnection();

        }
    }

    private static String getResult(HttpMethodBase method) throws IOException {
        StringBuilder result = new StringBuilder();
        String contentEncoding = null;

        Header header = method.getResponseHeader(Const.HttpHeader.CONTENT_ENCODING);
        if (header != null) {
            contentEncoding = method.getResponseHeader(Const.HttpHeader.CONTENT_ENCODING).getValue();
        }
        InputStream inputStream = null;
        if (!StringUtil.isEmpty(contentEncoding) && contentEncoding.equalsIgnoreCase("gzip")) {
            inputStream = new GZIPInputStream(method.getResponseBodyAsStream());
        } else {
            inputStream = method.getResponseBodyAsStream();
        }

        // 在目标页面情况未知的条件下，不推荐使用getResponseBodyAsString()方法
        // String strGetResponseBody = post.getResponseBodyAsString();
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, method.getResponseCharSet()));

        String inputLine = null;

        StringBuilder content = new StringBuilder();
        while ((inputLine = in.readLine()) != null) {
            content.append(inputLine);
            content.append(Const.LINE_SPLITER);
        }
        Document doc = Jsoup.parse(content.toString());
        String contentCharset = getContentCharset(doc.head().childNodes());
        result.append(doc.html());

        in.close();

        return StringUtil.ConverterStringCode(result.toString(), method.getResponseCharSet(), contentCharset);
    }

    /**
     * Get charset from content. utf-8 will be return if the charset can not be found.
     * 
     * @param headNodes
     * @return
     */
    private static String getContentCharset(List<Node> headNodes) {
        String nodeHtml = null;
        for (Node node : headNodes) {
            nodeHtml = node.outerHtml();
            Matcher matcher = CHARSET_PATTERN.matcher(nodeHtml);
            if (matcher.find()) {
                return matcher.group(1);
            }
        }
        return Const.CHARSET;
    }
}
